/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

import React, { PureComponent } from "react";
import { connect } from "dva";
import { Map, Polygon, PolyEditor, Marker } from "react-amap";
import { Popover, message, Button } from "antd";
import AddressSearch from "./AddressSearch/index";
import LocationBar from "./LocationBar/index";
import PolygonMarker from "./PolygonMarker/index";
import styles from "./index.less";
import MapWrapper from "./MapWrapper";

const YOUR_AMAP_KEY = "22adf5db0a96791877b993befadefcc0";
const VERSION = "1.4.12";
const SelelectIcon = () => <div className="map-select-icon" />;

@connect(({ loading, scope, global }) => ({
  mapShrink: global.mapShrink,
  currentIndex: scope.currentIndex,
  polygons: scope.list,
  getting: loading.effects["scope/getScopeList"],
  deletting: loading.effects["scope/scopeDelete"],
  freezing: loading.effects["scope/scopeFreeze"],
  saving: loading.effects["scope/scopeAdd"],
}))
class KbMap extends PureComponent {
  constructor(props) {
    super(props);
    // 地图事件
    this.amapEvents = {
      click: data => {
        const {
          lnglat: { lat, lng },
        } = data;
        this.handleSelect({
          location: {
            lat,
            lng,
          },
        });
      },
      created: map => {
        this.map = map;
      },
    };
    const saveAndDelete = (type, ins, item) => {
      const { id, tmpId } = item;
      this[type][id] = ins;
      if (id !== tmpId && this[type][tmpId]) {
        delete this[type][tmpId];
      }
    };
    // 矢量多边形事件
    this.polygonEvents = {
      created: ins => {
        const {
          extData: { item },
        } = ins.getOptions();
        saveAndDelete("polygons", ins, item);
      },
      click: e => {
        const {
          extData: { index, item },
        } = e.target.getOptions();
        this.handleSelectPolygon(index);
        this.handleEditor({ ...item, active: false }, index, e);
      },
      dragend: e => {
        // 监控拖动，同步更新polygons
        const {
          extData: { index, item },
        } = e.target.getOptions();
        this.handleDragend(e.target.getPath(), item, index);
      },
    };
    // 多边形编辑事件
    this.polygonEditorEvents = {
      created: (ins, item) => {
        saveAndDelete("polyEditors", ins, item);
      },
      adjust: e => {
        // 监控编辑变化，同步更新polygons
        const {
          extData: { index },
        } = e.target.getOptions();
        this.setCurrentIndex(index);
        this.updatePolygons(
          {
            area_detail: e.target.getPath(),
          },
          index
        );
      },
    };

    this.state = {
      screen: "normal",
    };
    this.polyEditors = {};
    this.polygons = {};
  }

  stopTimer = () => {
    this.timer && clearTimeout(this.timer);
  };

  componentDidMount() {
    this.getScopeList(() => {
      // 初次加载，待地图加载完全后，定位到指定位置（目前定位优先）
      this.timer = setTimeout(() => {
        const { polygons, currentIndex } = this.props;
        if (polygons && polygons[currentIndex]) {
          this.handleSelectPolygon(currentIndex);
        }
      }, 500);
    });
    document.addEventListener("keyup", this.handleListener);
  }

  componentWillUnmount() {
    document.removeEventListener("keyup", this.handleListener);
    // 停止监控
    this.stopTimer();
    // 销毁地图
    this.map.destroy();
  }

  // 获取范围列表
  getScopeList = then => {
    const { dispatch } = this.props;
    dispatch({
      type: "scope/getScopeList",
    }).then(then);
  };

  // id开头为tem_ 的则为临时id，表示新增的范围，还未保存
  isTemData = id => {
    return /^tem_*/.test(id);
  };

  // 获取中心点容器坐标
  getCenterPixel = () => {
    if (!this.centerPosition) {
      return { x: 0, y: 0 };
    }
    // 构造成 LngLat 对象后传入
    const [lng, lat] = this.centerPosition;
    return this.map.lngLatToContainer(new AMap.LngLat(lng, lat)); // 获得 Pixel 对象
  };

  // 增加临时数据
  handleAdd = () => {
    const newPolygons = [...(this.props.polygons || [])];
    const pixels = [[0, 100], [100, -100], [-100, -100]];
    const area_detail = [];
    // 中心点容器坐标
    const { x: cx, y: cy } = this.getCenterPixel();
    // 根据中心点生成三角形
    pixels.map(item => {
      const [x, y] = item;
      const pixel = new AMap.Pixel(x + cx, y + cy);
      const { lng, lat } = this.map.containerToLngLat(pixel);
      area_detail.push({ lng, lat });
    });
    const lastIndex = newPolygons.length;
    const id = `tem_${new Date().getTime()}`;
    newPolygons.push({
      id,
      status: 1,
      active: true,
      area_name: `配送范围${1 + lastIndex}`,
      area_detail,
      tmpId: id,
    });
    this.setCurrentIndex(lastIndex);
    this.saveScopeList(newPolygons);
    this.setZoomAndCenter(this.centerPosition || [area_detail[0].lng, area_detail[0].lat], false);
  };

  // 保存配送范围列表
  saveScopeList = list => {
    this.props.dispatch({
      type: "scope/saveScopeList",
      payload: {
        list,
      },
    });
  };

  // 删除
  handleDelete = (data, index) => {
    const { dispatch } = this.props;
    const { id, active } = data;
    const callback = () => {
      // 关闭当前的编辑状态
      if (active) {
        this.polyEditors[id].close();
      }
      delete this.polygons[id];
      delete this.polyEditors[id];

      this.updatePolygons(null, index);
    };
    if (this.isTemData(id)) {
      // 新增未保存的数据，直接删除
      callback();
      return;
    }
    dispatch({
      type: "scope/scopeDelete",
      payload: {
        id,
        status: 2,
      },
      then: res => {
        if (res.code == 0) {
          callback();
        }
      },
    });
  };

  // 选中当前区域，并缩放至合适显示范围
  handleSelectPolygon = (index, then) => {
    const { polygons } = this.props;
    const { id } = polygons[index];
    const currentPolygons = this.polygons[id];
    this.setCurrentIndex(index, () => {
      if (currentPolygons && this.map) {
        this.map.setFitView([currentPolygons]);
      }
      then && then();
    });
  };

  // 更新区域范围数据；data为null时将删除index对应项
  updatePolygons = (data, index) => {
    const { polygons } = this.props;
    const newPolygons = [...(polygons || [])];
    if (data) {
      newPolygons.splice(index, 1, { ...polygons[index], ...data });
    } else {
      newPolygons.splice(index, 1);
    }
    this.saveScopeList(newPolygons);
  };

  // 编辑、保存；注：切换编辑状态时 当前active反向
  handleEditor = (data, index, e) => {
    const { polygons } = this.props;
    const { active, id, area_name } = data;
    // 新增数据，判断是否重名
    if (active) {
      //无重名，执行保存
      const rename = polygons.filter(item => item.area_name === area_name && id !== item.id);
      if (rename.length > 0) {
        message.error("存在重复的配送范围名称，请修改");
        return;
      }
      // 上传最新记录
      this.handleSave(index);
    }
    this.updatePolygons({ ...data, active: !active }, index);
    if (active && e) {
      e.stopPropagation();
    }
  };

  // 监控退出全屏操作
  handleListener = e => {
    if (e.keyCode === 27 && this.state.screen === "full") {
      this.setState({
        screen: "normal",
      });
    }
  };
  // 全屏切换
  handleFullScreen = () => {
    const screen = this.state.screen === "full" ? "normal" : "full";
    if (screen === "full") {
      message.info("按Esc退出");
    }
    this.setState({
      screen,
    });
  };

  // 冻结、开启
  handleFreeze = (data, index) => {
    const { dispatch } = this.props;
    const { id, status } = data;
    const nextStatus = status == 1 ? "0" : "1";
    dispatch({
      type: "scope/scopeFreeze",
      payload: {
        id,
        status: nextStatus,
      },
      then: res => {
        if (res.code == 0) {
          this.updatePolygons({ status: nextStatus }, index);
        }
      },
    });
  };

  // 定位
  handleLocation = (data, status) => {
    const {
      action,
      position: { lat: latitude, lng: longitude },
      address,
    } = data;
    const { polygons } = this.props;
    const polygonsLength = polygons ? polygons.length : 0;
    this.setState({
      currentAddress: address,
      currentPosition: {
        latitude,
        longitude,
      },
    });
    this.centerPosition = [longitude, latitude];
    if (action !== "init" || polygonsLength === 0) {
      this.setZoomAndCenter();
    }
    if (status === "error") {
      message.error("定位失败，建议您输入关键字搜索！");
      this.searchNode && this.searchNode.onFocus();
    }
  };

  // 搜索点选、搜索点移动、点选
  handleSelect = data => {
    const {
      location: { lat: latitude, lng: longitude },
      district,
      name,
      address,
    } = data;
    this.setState({
      selectPosition: {
        latitude,
        longitude,
      },
      selectInfo: address ? (
        <div className="map-address-tips">
          <div>
            <span className="map-tips-name">{name}</span>
            {district && <span className="map-tips-district">{district}</span>}
          </div>
          <div className="map-tips-detail">{address}</div>
        </div>
      ) : null,
    });
    this.centerPosition = [longitude, latitude];
    this.setZoomAndCenter();
  };

  // 拖拽结束
  handleDragend = (area_detail, data, index) => {
    this.handleSelectPolygon(index, () => {
      this.handleEditor({ ...data, area_detail, active: false }, index);
    });
  };

  // 设置当前高亮索引
  setCurrentIndex = (currentIndex, then) => {
    this.setState(
      {
        currentIndex,
      },
      then
    );
    this.props.dispatch({
      type: "scope/save",
      payload: {
        currentIndex,
      },
    });
  };

  // 保存编辑结果
  handleSave = index => {
    const { dispatch, polygons } = this.props;
    const { id, status, area_name, area_detail } = polygons[index];
    const newArea = area_detail.map(item => {
      const { lat, lng } = item;
      return {
        lat,
        lng,
      };
    });
    const payload = {
      area_name,
      status,
      area_detail: newArea,
    };
    if (!this.isTemData(id)) {
      // 编辑
      payload.id = id;
    }
    dispatch({
      type: "scope/scopeAdd",
      payload,
      then: res => {
        if (res.code == 0) {
          if (res.data) {
            const currentId = res.data.id || payload.id;
            this.updatePolygons(
              {
                active: false,
                area_detail: newArea,
                id: currentId,
              },
              index
            );
          }
        } else {
          // 重新唤起编辑
          this.handleEditor({ ...data, active: false }, index);
        }
      },
    });
  };

  // 移动至中心点，并缩放到15级
  setZoomAndCenter = (postion, zoom = true) => {
    const centerPosition = postion || this.centerPosition;
    if (zoom) {
      this.map.setZoomAndCenter(15, centerPosition);
    } else {
      this.map.setCenter(centerPosition);
    }
  };

  render() {
    const { zoom = 15, deletting, saving, freezing, getting, polygons } = this.props;
    const {
      screen,
      currentIndex,
      currentAddress,
      currentPosition,
      selectInfo,
      selectPosition,
    } = this.state;
    const polygonStyle = {
      strokeStyle: "solid",
      strokeColor: "#1791fc",
      fillColor: "#1791fc",
      strokeOpacity: 0.8,
      strokeWeight: 3,
      fillOpacity: 0.35,
    };
    return (
      <div className={`${styles.kbmap} ${screen}-screen`}>
        <Map events={this.amapEvents} amapkey={YOUR_AMAP_KEY} version={VERSION} zoom={zoom}>
          {!getting &&
            polygons &&
            polygons.map((item, index) => {
              const { area_detail, active, status, id } = item;
              const opacityStyle =
                currentIndex === index
                  ? {
                      fillOpacity: 0.35,
                      strokeOpacity: 0.8,
                    }
                  : {
                      fillOpacity: 0.1,
                      strokeOpacity: 0.4,
                    };
              return (
                <Polygon
                  draggable
                  style={
                    status != 1
                      ? {
                          ...polygonStyle,
                          strokeColor: "#f5222d",
                          strokeStyle: "dashed",
                          fillColor: "#f5222d",
                          ...opacityStyle,
                        }
                      : {
                          ...polygonStyle,
                          ...opacityStyle,
                        }
                  }
                  path={area_detail}
                  key={id}
                  extData={{ index, item }}
                  events={this.polygonEvents}
                >
                  <PolyEditor
                    active={active}
                    events={{
                      ...this.polygonEditorEvents,
                      created: ins => {
                        this.polygonEditorEvents.created(ins, item, index);
                      },
                    }}
                  />
                </Polygon>
              );
            })}
          <MapWrapper className="map-top-bar">
            <AddressSearch onSelect={this.handleSelect} ref={node => (this.searchNode = node)} />
            <LocationBar onLocation={this.handleLocation} />
            <Button
              onClick={this.handleFullScreen}
              className="map-fullscreen"
              icon={screen === "full" ? "fullscreen-exit" : "fullscreen"}
            />
          </MapWrapper>
          {selectPosition && (
            <Marker
              events={{
                dragend: data => {
                  const {
                    lnglat: { lat, lng },
                  } = data;
                  this.handleSelect({
                    location: {
                      lat,
                      lng,
                    },
                  });
                },
              }}
              cursor="move"
              draggable
              raiseOnDrag
              render={() => {
                return selectInfo ? (
                  <Popover content={<div>{selectInfo}</div>}>
                    <div>
                      <SelelectIcon />
                    </div>
                  </Popover>
                ) : (
                  <SelelectIcon />
                );
              }}
              position={selectPosition}
            />
          )}
          {currentPosition && (
            <Marker
              position={currentPosition}
              clickable
              render={() => {
                return (
                  <Popover
                    content={
                      <div style={{ color: "#999" }}>
                        我在
                        <span style={{ color: "#333", marginLeft: 5 }}>{currentAddress}</span>
                      </div>
                    }
                  >
                    <div className="map-location-icon" />
                  </Popover>
                );
              }}
            />
          )}
          <PolygonMarker
            getting={getting}
            deletting={deletting}
            saving={saving}
            freezing={freezing}
            currentIndex={currentIndex}
            isTemData={this.isTemData}
            onAdd={this.handleAdd}
            onEditor={this.handleEditor}
            onFreeze={this.handleFreeze}
            onDelete={this.handleDelete}
            onSelect={this.handleSelectPolygon}
            polygons={polygons}
          />
        </Map>
      </div>
    );
  }
}

export default KbMap;
